#include <functional>
#include <iostream>
#include "threadpool.h"

namespace QinChat{
    namespace Core{
        CThreadPool::CThreadPool(size_t nThreadSize /*= 2 */):m_bExit(false){
            m_idlThrNum = nThreadSize < 1 ? 1 : nThreadSize;

            for (size_t index = 0; index < m_idlThrNum; ++index){
                std::unique_ptr<std::thread> pThread(new std::thread(std::bind(&CThreadPool::WorkTask, this)));
                m_workThreads.push_back(std::move(pThread));
            }
        }

        CThreadPool::~CThreadPool(){
            Stop();
            Clear();
        }

        void CThreadPool::PushTask(std::shared_ptr<CTask>& task){
			
            std::cout<<"push task"<<this<<std::endl;
			if (m_bExit.load()){
                return;
            }
			std::cout<<"push task\n";
            std::unique_lock<std::mutex> lock(m_mutex);
            std::cout<<"push task\n";
            m_listTask.Push(task);
            m_condition.notify_one();
        }

        void CThreadPool::WorkTask(void){
            while(!m_bExit)  {
				std::cout<<"WorkTask"<<this<<std::endl;
                std::shared_ptr<CTask> pTask = GetTask();
                if (nullptr == pTask){
                    continue;
                }
                --m_idlThrNum;
                (*pTask)();
                ++m_idlThrNum;
            }

        }

        std::shared_ptr<CTask> CThreadPool::GetTask(){
            std::unique_lock<std::mutex> lock(m_mutex);
			
            m_condition.wait(lock, [this]
			{return this->m_bExit.load() || !this->m_listTask.IsEmpty();});
            if (m_bExit && m_listTask.IsEmpty()){
                return nullptr;
            }

            std::shared_ptr<CTask> pTask = m_listTask.Front();
            m_listTask.Pop();
            return pTask;
        }

        void CThreadPool::Clear(void){
            
            m_condition.notify_all();

            for (size_t index = 0; index < m_workThreads.size(); ++index){
                m_workThreads[index]->join();
            }
            
            m_workThreads.clear();
        }

        void CThreadPool::Stop(void){
            std::unique_lock<std::mutex> lock(m_mutex);
            m_bExit = true;
        }
    }
}